package org.zoomdev.zoom.dao.impl;

import org.zoomdev.zoom.dao.Ar;
import org.zoomdev.zoom.dao.ConnectionExecutor;
import org.zoomdev.zoom.dao.Dao;
import org.zoomdev.zoom.dao.Entity;
import org.zoomdev.zoom.dao.ResultSetParser;
import org.zoomdev.zoom.dao.transaction.Transactions;
import org.zoomdev.zoom.dao.utils.DaoUtils;

import javax.sql.DataSource;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;

public class ArImpl<T> implements Ar<T> {

    static ResultSetParser countParser = rs -> {
        rs.next();
        return rs.getInt(1);
    };
    private final Dao dao;
    protected SimpleSelect select = new SimpleSelect();
    //默认entity
    protected SqlConfig config = new SqlConfig();
    private final ConnectionExecutor updateExecutor = connection -> {
        try (PreparedStatement ps = connection.prepareStatement(config.sql.toString())) {
            config.prepare(ps);
            return ps.executeUpdate();
        }
    };
    protected Class<T> type;
    protected String table;
    DataSource ds;
    Transactions transactions;
    Entity<T> entity;
    private final ConnectionExecutor insertExecutor = connection -> {
        try (PreparedStatement ps = entity.prepareInsert(connection, config.sql.toString())) {
            config.prepare(ps);
            return ps.executeUpdate();
        }
    };

    public ArImpl(Dao dao, Transactions transactions) {
        this.transactions = transactions;
        this.dao = dao;
        this.ds = dao.dataSource();
    }

    @Override
    public Ar<T> type(Class<T> type) {
        this.type = type;
        return this;
    }

    @Override
    public Ar<T> table(String table) {
        this.table = table;
        return this;
    }

    @Override
    public Ar<T> entity(Entity<T> entity) {
        this.entity = entity;
        return this;
    }

    @Override
    public Ar ignoreNull() {
        config.ignoreNull = true;
        return this;
    }

    public Ar beginBatch() {
        return this;
    }

    public List<Integer> commitBatch() {
        return null;
    }

    public Ar set(T data) {
        return this;
    }

    public int update(T data) {
        entity.buildUpdate(data, select, config);
        return execute(updateExecutor);
    }

    @Override
    public int delete(T data) {
        return 0;
    }

    public int insert(T data) {
        entity.buildInsert(data, select, config);
        return execute(insertExecutor);
    }

    public int update() {
        return execute(updateExecutor);
    }

    public int count() {
        select.buildSelectForCount(config.sql);
        return (Integer) query(countParser);
    }

    public List<T> find() {
        entity.buildSelect(select, config);
        return (List<T>) query(DaoUtils.getListParser(entity));
    }

    @Override
    public T get(Object... args) {
        return null;
    }

    @Override
    public Ar<T> select(String select) {
        return null;
    }

    @Override
    public Ar<T> filter(String filter) {
        return null;
    }


    <T> T execute(ConnectionExecutor executor) {
        try {
            return transactions.execute(ds, executor);
        } finally {
            config.clear();
            select.clear();
        }
    }


    ConnectionExecutor getQueryExecutor(ResultSetParser parser) {
        return connection -> {
            try (PreparedStatement ps = connection.prepareStatement(config.sql.toString())) {
                config.prepare(ps);
                try (ResultSet rs = ps.executeQuery()) {
                    return parser.fromResultSet(rs);
                }
            }
        };
    }


    Object query(ResultSetParser parser) {
        return execute(getQueryExecutor(parser));
    }


}
